/* Filename: block.c
 * No.76.信号集
 * Description:
 * 每秒打印一个*，打印5个*就换行。中途收到1个或多个SIGINT(CTRL+C)信号暂不处理，等第5个*后只处理1个
 * Last modified: humble 20200404 10:41
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

//二选一
//#define demo0 (1)
#define demo1 (1)

#if demo0
#define _SAVESET_ (1)
#else
#define _SAVESET_ (0)
#endif

static void usage(void);

void int_handler(int i)
{
    write(1, "!", 1);
}

int main(int argc, char **argv)
{
    int i;
    sigset_t set, oset, saveset;

    if(argc != 1){
        fprintf(stderr, "argc !=1");
        usage();
        exit(1);
    }

    signal(SIGINT, int_handler);
    sigemptyset(&set);
    sigaddset(&set, SIGINT);

#if _SAVESET_
    //此句目的在于保存当前mask到saveset，方便以后恢复，用SIG_UNBLOCK或SIG_BLOCK都无所谓
    sigprocmask(SIG_UNBLOCK, &set, &saveset);
#endif

    while(1){
        //1.把当前的mask保存到oset内(方便以后恢复)，如果为NULL表示不保存
        //2.把set指定的信号阻塞住（即把mask的对应bit清零）
        //那么收到set指定的信号(padding对应bit被置一)，也不会被处理(因为 mask&padding 中信号对应bit不为1)
        sigprocmask(SIG_BLOCK, &set, &oset);

        for(i = 0; i < 5; i++)
        {
            write(1, "*", 1);
            sleep(1);
        }
        write(1, "\n", 1);

#if demo0
        //把set指定的信号取消阻塞住（即把mask的对应bit置一）
        //那么收到set指定的信号(padding对应bit被置一)，就会被处理(因为 mask&padding 中信号对应bit为1)
        //问题：假如原本set指定的一或多个信号一开始就是BLOCK状态，那执行完下面这句它(们)就变为了UNBLOCK。
        //应该改为：原本是什么状态，最后又恢复到什么状态。定义_SAVESET_为1即可
        sigprocmask(SIG_UNBLOCK, &set, NULL);
#elif demo1
        //1.把当前的mask保存到NULL内，也就是不保存
        //2.把mask设置为oset(相当于恢复了之前的状态)
        //那么收到oset指定的信号(padding对应bit被置一)，就会被处理(因为 mask&padding 中信号对应bit为1)
        //另外，用oset好处是：原本是什么状态，最后又恢复到什么状态。则_SAVESET_不需要定义为1
        sigprocmask(SIG_SETMASK, &oset, NULL);
#endif
    }

#if _SAVESET_
    //把mask设置为saveset(相当于恢复了之前的状态)
    sigprocmask(SIG_SETMASK, &saveset, NULL);
#endif

    return 0;
}

static void usage(void)
{
#define USAGE "Usage:\n\
  Helloworld\n"
    printf(USAGE);
}
